package i3.ui.option;

import i3.swing.Bind.Binding;
import i3.swing.component.KeyCapturer;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Insets;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.ListCellRenderer;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.ScrollPaneConstants;
import javax.swing.border.BevelBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.netbeans.validation.api.Problem;
import org.netbeans.validation.api.Problems;
import org.netbeans.validation.api.Severity;
import org.netbeans.validation.api.Validator;
import org.netbeans.validation.api.ui.ValidationUI;
import org.netbeans.validation.api.ui.swing.SwingValidationGroup;

/**
 *
 * @author i30817
 */
public final class ShortcutOptions extends javax.swing.JPanel implements Iterable<Entry<Binding, KeyStroke>> {


    /**
     * Creates a shortcut options panel.
     */
    public ShortcutOptions() {
        super();
        initComponents();
        keyCapturer.addPropertyChangeListener(KeyCapturer.CAPTURED_KEYSTROKE, new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent arg0) {
                if (arg0.getNewValue() != null) {
                    keyStrokeMap.put(shortcutKeysList.getSelectedValue(), (KeyStroke) arg0.getNewValue());
                }
            }
        });
    }

    public void setupValidation(SwingValidationGroup group) {
        KeyStrokesNotEqual noEqualKeyStrokes = new KeyStrokesNotEqual(group.createProblemLabel());
        group.add(keyCapturer, noEqualKeyStrokes);
        group.addUI(noEqualKeyStrokes);
        shortcutKeysList.setCellRenderer(noEqualKeyStrokes);
    }

    public ShortcutOptions(String string, String string0) {
        this();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jScrollPane1 = new JScrollPane();
        shortcutKeysList = new JList<>(new DefaultListModel<Binding>());
        textPane = new JTextArea();
        keyCapturer = new KeyCapturer();

        jScrollPane1.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

        shortcutKeysList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        shortcutKeysList.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent evt) {
                shortcutKeysListValueChanged(evt);
            }
        });
        jScrollPane1.setViewportView(shortcutKeysList);

        textPane.setColumns(20);
        textPane.setEditable(false);
        textPane.setLineWrap(true);
        textPane.setRows(5);
        textPane.setWrapStyleWord(true);
        textPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        textPane.setFocusable(false);
        textPane.setMargin(new Insets(3, 3, 3, 3));
        textPane.setMinimumSize(new Dimension(0, 0));
        textPane.setOpaque(false);

        keyCapturer.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
        keyCapturer.setHorizontalAlignment(JTextField.CENTER);

        GroupLayout layout = new GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(Alignment.LEADING).addGroup(layout.createSequentialGroup()
                .addContainerGap()

                .addComponent(jScrollPane1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE).addPreferredGap(ComponentPlacement.RELATED).addGroup(layout.createParallelGroup(Alignment.LEADING).addComponent(textPane, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addComponent(keyCapturer, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)).addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(Alignment.LEADING).addGroup(Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()

                .addGroup(layout.createParallelGroup(Alignment.TRAILING).addGroup(Alignment.LEADING, layout.createSequentialGroup()

                        .addComponent(textPane, GroupLayout.PREFERRED_SIZE, 177, GroupLayout.PREFERRED_SIZE).addPreferredGap(ComponentPlacement.RELATED, 11, Short.MAX_VALUE).addComponent(keyCapturer, GroupLayout.PREFERRED_SIZE, 44, GroupLayout.PREFERRED_SIZE)).addComponent(jScrollPane1, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 232, Short.MAX_VALUE)).addContainerGap())
        );
    }// </editor-fold>//GEN-END:initComponents

    private void shortcutKeysListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_shortcutKeysListValueChanged
        if (evt.getValueIsAdjusting()) {
            return;
        }
        updateView();
    }//GEN-LAST:event_shortcutKeysListValueChanged

    private void updateView() {
        if (shortcutKeysList.getSelectedIndex() == -1) {
            shortcutKeysList.setSelectedIndex(0);
        }
        Binding key = shortcutKeysList.getSelectedValue();
        textPane.setText((String) key.getAction().getValue(Action.LONG_DESCRIPTION));
        KeyStroke current = keyStrokeMap.get(key);
        keyCapturer.setKeyStroke(current);
    }

    private void addShortcutOption(Binding key, KeyStroke newKeystroke) {
        if (key == null) {
            throw new IllegalArgumentException("Name: (" + key + ") is null");
        }
        if (newKeystroke == null) {
            return;//skip keys corresponding to null keystrokes
        }

        if (!keyStrokeMap.containsKey(key)) {
            DefaultListModel<Binding> mod = (DefaultListModel<Binding>) shortcutKeysList.getModel();
            mod.addElement(key);
        }
        keyStrokeMap.put(key, newKeystroke);
        firePropertyChange(key.toString(), null, newKeystroke);
    }

    public void putAll(Iterable<Entry<Binding, KeyStroke>> iterable) {
        for (Entry<Binding, KeyStroke> e : iterable) {
            addShortcutOption(e.getKey(), e.getValue());
        }
        updateView();
    }

    @Override
    public Iterator<Entry<Binding, KeyStroke>> iterator() {
        return keyStrokeMap.entrySet().iterator();
    }

    public void updateSize() {
        int width = 1;
        ListModel<Binding> m = shortcutKeysList.getModel();
        ListCellRenderer<? super Binding> lcr;
        lcr = shortcutKeysList.getCellRenderer();
        for (int i = 0; i < m.getSize(); i++) {
            Binding o = m.getElementAt(i);
            Component c = lcr.getListCellRendererComponent(shortcutKeysList, o, 0, false, false);
            Dimension dim = c.getPreferredSize();
            width = Math.max(dim.width, width);
        }
        width = (int) (width + jScrollPane1.getVerticalScrollBar().getPreferredSize().getWidth());
        jScrollPane1.setPreferredSize(new Dimension(width, -1));
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private JScrollPane jScrollPane1;
    private KeyCapturer keyCapturer;
    private JList<Binding> shortcutKeysList;
    private JTextArea textPane;
    // End of variables declaration//GEN-END:variables
    private Map<Binding, KeyStroke> keyStrokeMap = new HashMap<>();

    private class KeyStrokesNotEqual implements Validator<String>, ValidationUI, ListCellRenderer<Binding> {

        ListCellRenderer<? super Binding> renderer = shortcutKeysList.getCellRenderer();
        Component errorCell;
        int loc;

        public KeyStrokesNotEqual(Component errorCell) {
            this.errorCell = errorCell;
        }
        
        @Override
        public Component getListCellRendererComponent(JList<? extends Binding> list, Binding value, int index, boolean isSelected, boolean cellHasFocus) {
            if (loc == index) {
                return errorCell;
            }
            return renderer.getListCellRendererComponent(shortcutKeysList, value, index, isSelected, cellHasFocus);
        }

        @Override
        public void validate(Problems prblms, String string, String t) {
            KeyStroke newStroke = keyCapturer.getKeyStroke(), old = null;
            //if stroke is null (no new value) just check the old ones)
            if (newStroke != null) {
                old = keyStrokeMap.put(shortcutKeysList.getSelectedValue(), newStroke);
            }
            HashSet<KeyStroke> validation = new HashSet<>();
            for (KeyStroke st : keyStrokeMap.values()) {
                if (validation.contains(st)) {
                    prblms.add("Shortcut is already set", Severity.FATAL);
                    break;
                }
                validation.add(st);
            }
            if (newStroke != null) {
                keyStrokeMap.put(shortcutKeysList.getSelectedValue(), old);
            }
            validation.clear();
        }

        @Override
        public Class<String> modelType() {
            return String.class;
        }

        @Override
        public void clearProblem() {
            loc = -1;
            shortcutKeysList.setEnabled(true);
        }

        @Override
        public void showProblem(Problem prblm) {
            loc = shortcutKeysList.getSelectedIndex();
            shortcutKeysList.setEnabled(false);
        }
    }
}
